﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EzDesk.Apps.Model.Attendance;
using EzDesk.Utility.Extensions;
using EzDesk.Utility.Json;
using EzDesk.Utility.ServiceStatusInfo;

namespace EzDesk.Apps.ServiceImpl.Attendance
{
    public partial class AttendanceService
    {
        #region [ private methods ]

        /// <summary>
        /// 申请新的假期之后，发送Feed
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="date"></param>
        /// <param name="applyText"></param>
        private void sendApplyLeaveFeed(LeaveInfo leaveInfo)
        {
            var senderUser = _ezApiClient.GetSimpleUserById(leaveInfo.UserId);
            var feedData = new Dictionary<string, string>
                               {
                                   {"senderName", senderUser.Name},
                                   {"leaveId", leaveInfo.Id.ToString()},
                                   {"leaveType", leaveInfo.LeaveTypeName},
                                   {
                                       "applyText",
                                       string.IsNullOrEmpty(leaveInfo.Description)
                                           ? ""
                                           : string.Format("\"{0}\"", leaveInfo.Description)
                                       }
                               };

            // 发送目标为所有所有公司boss
            var memberString = _ezApiClient.GetGroupByName("core_boss").MemberString;

            var feedId = _ezApiClient.SendFeed(
                FeedTemplateStr_attendance_applyLeave,
                JsonHelper.ConvertToJson(feedData),
                memberString
                );

            _ezApiClient.SetFeedRecord(leaveInfo.Id, FeedTemplateStr_attendance_applyLeave, memberString, feedId, null);
        }

        /// <summary>
        /// 审批假期成功之后，发送Feed
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="date"></param>
        /// <param name="applyText"></param>
        private void sendAuditLeaveSuccFeed(Guid auditUserId, LeaveInfo leaveInfo)
        {
            var auditUser = _ezApiClient.GetSimpleUserById(auditUserId);

            var feedData = new Dictionary<string, string>
                               {
                                   {"auditUserName", auditUser.Name},
                                   {"currentTime", DateTime.Now.ToEpoch().ToString()},
                                   {"leaveType", leaveInfo.LeaveTypeName},
                                   {
                                       "auditText",
                                       string.IsNullOrEmpty(leaveInfo.AuditNote)
                                           ? ""
                                           : string.Format("<ez:br />\"{0}\"", leaveInfo.AuditNote)
                                       },
                               };

            // 发送目标 请假申请发出者
            var memberString = leaveInfo.UserId.ToString();

            var feedId = _ezApiClient.SendFeed(
                FeedTemplateStr_attendance_auditLeaveSucc,
                JsonHelper.ConvertToJson(feedData),
                memberString
                );
        }

        /// <summary>
        /// 审批假期拒绝之后，发送Feed
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="date"></param>
        /// <param name="applyText"></param>
        private void sendAuditLeaveRejectedFeed(Guid auditUserId, LeaveInfo leaveInfo)
        {
            var auditUser = _ezApiClient.GetSimpleUserById(auditUserId);

            var feedData = new Dictionary<string, string>
                               {
                                   {"auditUserName", auditUser.Name},
                                   {"currentTime", DateTime.Now.ToEpoch().ToString()},
                                   {"leaveType", leaveInfo.LeaveTypeName},
                                   {
                                       "auditText",
                                       string.IsNullOrEmpty(leaveInfo.AuditNote)
                                           ? ""
                                           : string.Format("\"{0}\"<ez:br />", leaveInfo.AuditNote)
                                       },
                               };

            // 发送目标 请假申请发出者
            var memberString = leaveInfo.UserId.ToString();

            var feedId = _ezApiClient.SendFeed(
                FeedTemplateStr_attendance_auditLeaveRejected,
                JsonHelper.ConvertToJson(feedData),
                memberString
                );
        }


        /// <summary>
        /// 判断假期是否重复
        /// </summary>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <returns></returns>
        private bool isDuplicateLeave(DateTime startTime, DateTime endTime, Guid userId)
        {
            // 找出没审核或者是审核没通过的
            var infoList = _leaveInfoRepository.GetAll()
                .Where(p=>p.UserId == userId)
                .Where(p=>p.StartTime <= endTime && p.EndTime >= startTime)
                .Where(p => !p.IsAudited || p.IsAgreed);
            return infoList.Count() > 0;
        }

        #endregion

        #region [ about Leaves ]
        /// <summary>
        /// 获得当前所有的请假类型
        /// </summary>
        /// <returns></returns>
        public StatusInfo<List<LeaveType>> GetAllLeaveTypes()
        {
            return StatusInfo.Wrap(
                () =>
                    {
                        return _leaveTypeRepository.GetAll().ToList();
                    });
        }

        /// <summary>
        /// 通过ID获得一种请假类型
        /// </summary>
        /// <param name="leaveTypeId"></param>
        /// <returns></returns>
        public StatusInfo<LeaveType> GetLeaveTypeyById(Guid leaveTypeId)
        {
            return StatusInfo.Wrap(
                () =>
                    {
                        return _leaveTypeRepository.GetById(leaveTypeId);
                    });
        }

        /// <summary>
        /// 获得某人一天的假期等情况
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        public StatusInfo<DayInfo> GetDayInfo(Guid userId, DateTime date)
        {
            return StatusInfo.Wrap(
                () =>
                    {
                        var legalHolday = _legalHolidayRepository.GetLegalHolidayInfo(date);
                        var extraShift = _extraShiftRepository.GetExtraShiftInfo(date);

                        return new DayInfo(date)
                                   {
                                       HolidayInfo = legalHolday,
                                       ExtraShiftInfo = extraShift,
                                   };
                    });
        }

        /// <summary>
        /// 获得某人一天中的请假情况
        /// </summary>
        /// <param name="CurrentUserId"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        public StatusInfo<DayLeaveInfo> GetDayLeaveInfo(Guid userId, DateTime date)
        {
            return StatusInfo.Wrap(
                () =>
                    {
                        // 获得包含当天本人的所有请假记录
                        var startTime = date.Date;
                        var endTime = date.Date.AddDays(1);
                        List<LeaveInfo> leaveList = _leaveInfoRepository.GetLeaveInfoList(
                            startTime,
                            endTime,
                            null,
                            null,
                            userId,
                            isAudited: true,
                            isAgreed: null
                            );

                        var dayleaveInfo = new DayLeaveInfo(date);
                        var theDayOnDutyTime = attendanceConfig.StdOnDutyTime.ToDateTime(date);
                        var theDayOffDutyTime = attendanceConfig.StdOffDutyTime.ToDateTime(date);

                        foreach (var leaveInfo in leaveList)
                        {
                            // 为每条请假记录生成一条dayLeaveItem
                            var dayLeaveItem = new DayLeaveInfoItem()
                                                   {
                                                       Day = date,
                                                       LeaveId = leaveInfo.Id,
                                                       StartTime =
                                                           theDayOnDutyTime > leaveInfo.StartTime
                                                               ? theDayOnDutyTime
                                                               : leaveInfo.StartTime,
                                                       EndTime =
                                                           theDayOffDutyTime < leaveInfo.EndTime
                                                               ? theDayOffDutyTime
                                                               : leaveInfo.EndTime,
                                                       IsForWork = leaveInfo.IsForWork,
                                                       LeaveName = leaveInfo.LeaveTypeName,
                                                   };
                            dayleaveInfo.Leaves.Add(dayLeaveItem);

                            // 假期 是否撑满了全天
                            if (leaveInfo.StartTime <= theDayOnDutyTime &&
                                leaveInfo.EndTime >= theDayOffDutyTime)
                            {
                                dayleaveInfo.IsWholeDay = true;
                            }
                        }

                        return dayleaveInfo;
                    });
        }

        /// <summary>
        /// 通过ID获得一个请假
        /// </summary>
        /// <param name="leaveId"></param>
        /// <returns></returns>
        public StatusInfo<LeaveInfo> GetLeaveInfoById(Guid leaveId)
        {
            return StatusInfo.Wrap(
                () =>
                    {
                        return convertLeaveInfoModel(_leaveInfoRepository.GetById(leaveId));
                    });
        }

        /// <summary>
        /// 获得一个请假记录
        /// </summary>
        /// <param name="startTime">开始时间</param>
        /// <param name="endTime">结束时间</param>
        /// <param name="userId">请假人ID</param>
        /// <param name="isAudited">是否已经审核</param>
        public StatusInfo<List<LeaveInfo>> GetLeaveInfoList(
            DateTime? startTime,
            DateTime? endTime,
            DateTime? createTimeStart,
            DateTime? createTimeEnd,
            Guid? userId,
            bool? isAudited,
            bool? isAgreed)
        {
            return StatusInfo.Wrap(
                () =>
                    {
                        return _leaveInfoRepository.GetLeaveInfoList(
                            startTime,
                            endTime,
                            createTimeStart,
                            createTimeEnd,
                            userId,
                            isAudited,
                            isAgreed
                            );
                    });
        }

        /// <summary>
        /// 申请一个新的假期
        /// </summary>
        /// <param name="info"></param>
        public StatusInfo ApplyLeave(LeaveInfo info)
        {
            return StatusInfo.Wrap(
                () =>
                    {
                        if (info.StartTime >= info.EndTime)
                        {
                            throw new Exception("假期开始时间必须早于假期结束时间。");
                        }
                        if (isDuplicateLeave(info.StartTime, info.EndTime, info.UserId))
                        {
                            throw new Exception("假期有重复");
                        }
                        //todo: 验证其他字段
                        info.CreateTime = DateTime.Now;
                        _leaveInfoRepository.Add(info, true);

                        // 向负责审批假期的员工发出Notification
                        sendApplyLeaveFeed(info);
                    });
        }

        public StatusInfo<bool> IsDuplicateLeave(DateTime startTime, DateTime endTime, Guid userId)
        {
            return StatusInfo.Wrap(
                () => isDuplicateLeave(startTime, endTime, userId)
                );
        }

        /// <summary>
        /// 对一个请假进行审批
        /// </summary>
        /// <param name="leaveInfoId">请假ID</param>
        /// <param name="isAgreed">是否同意请假</param>
        /// <param name="auditNote">审批备注</param>
        /// <param name="auditId">审批人Id</param>
        public StatusInfo AuditLeave(Guid leaveInfoId, bool isAgreed, string auditNote, Guid auditId)
        {
            return StatusInfo.Wrap(
                () =>
                    {
                        var leaveInfo = _leaveInfoRepository.GetById(leaveInfoId);
                        if (leaveInfo == null)
                        {
                            throw new Exception("未找到对应的信息");
                        }

                        leaveInfo.IsAudited = true;
                        leaveInfo.AuditUserId = auditId;
                        leaveInfo.AuditNote = auditNote;
                        leaveInfo.AuditTime = DateTime.Now;
                        leaveInfo.IsAgreed = isAgreed;

                        _leaveInfoRepository.Update(leaveInfo, true);

                        if (isAgreed)
                        {
                            // 向被审批的对象发出通知
                            sendAuditLeaveSuccFeed(auditId, leaveInfo);
                        }
                        else
                        {
                            // 发出被拒绝通知
                            sendAuditLeaveRejectedFeed(auditId, leaveInfo);
                        }

                        // 取消所有相关的要求审批的Notificaiton
                        var auditLeaveFeedId = Guid.Parse(
                            _ezApiClient.GetFeedRecord(leaveInfoId, FeedTemplateStr_attendance_applyLeave, null)
                            );
                        var memberstring = _ezApiClient.GetGroupByName("core_boss").MemberString;
                        _ezApiClient.SetFeedIsAvailable(auditLeaveFeedId, memberstring, false);

                        // todo: 通知所有人假期生效
                    });
        }

        #endregion
    }
}
